package com.kgis.map.geometry {
    import com.kgis.map.Map;
    import com.kgis.map.common.enum.GeoTypeEnum;
    import com.kgis.map.common.util.Evals;
    import com.kgis.map.common.util.GMath;
    import com.kgis.map.constant.LayerIdConstants;
    import com.kgis.map.feature.Feature;
    import com.kgis.map.geometry.AbstractGeometry;
    import com.kgis.map.geometry.IGeometry;
    import com.kgis.map.geometry.ILineGeometry;
    import com.kgis.map.geometry.IPointComposeGeometry;
    import com.kgis.map.geometry.PointGeometry;
    import com.kgis.map.geometry.basetype.Extent;
    import com.kgis.map.geometry.basetype.Location;
    import com.kgis.map.geometry.basetype.Pixel;
    import com.kgis.map.handler.feature.draw.AnchorPoint;
    import com.kgis.map.handler.feature.draw.snap.SnapTypeEnum;
    import com.kgis.map.layer.GraphicLayer;
    import com.kgis.map.style.IStyle;
    import com.kgis.map.style.PolylineStyle;
    
    import flash.display.Sprite;
    
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;

    /**
     * 简单线
     */
    [Bindable]
    [RemoteClass(alias="com.kgis.map.model.geometry.PolylineGeometry")]
    public class PolylineGeometry extends AbstractGeometry implements ILineGeometry, IPointComposeGeometry {
        private var _pointList:ArrayCollection = null;
		private var _duration:Number=0;

        public function PolylineGeometry() {
            super();
        }

        /**
         * 绘制polyline
         */
        override public function draw(sprite:Sprite, geoStyle:IStyle, map:Map):void {
            var nWidth:Number = 3;
            var nColor:uint = 0xFF0000;
            var nAlpha:Number = 1.0;

            if (!sprite) {
                trace("polyline sprite为空!");
                return;
            }
            var fea:Feature = sprite as Feature;
            if (!this.isValid()) {
                trace("线几何体不符合规范,polyline objectid=" + fea.objectId.toString());
                sprite.graphics.clear();
                return;
            }
            if (!map) {
                trace("map为空,polyline objectid=" + fea.objectId.toString());
                return;
            }

            var polylineStyle:PolylineStyle;
            var i:int = 0;
            if (geoStyle == null) {
                polylineStyle = PolylineStyle.getDefaultStyle();
            }
            else {
                polylineStyle = geoStyle as PolylineStyle;
            }

            if (!(polylineStyle is PolylineStyle)) {
                trace("线图形数据有误：objectid=" + fea.objectId.toString() + ",layerid=" + fea.layer.id.toString());
                sprite.graphics.clear();
                return;
            }

            var tempWidth:String;
            if (polylineStyle.width.length > map.zoom) {
                tempWidth = polylineStyle.width[map.zoom];
            }
            else {
                tempWidth = polylineStyle.width[0];
            }
            nWidth = Evals.getSizeByLevel(tempWidth, map.zoom);

            nColor = polylineStyle.color;
            nAlpha = polylineStyle.alpha;

            sprite.graphics.clear();
            sprite.graphics.lineStyle(nWidth, nColor, nAlpha, false, "normal", null, null, 3);

            var star_commands:Vector.<int> = new Vector.<int>();
            var star_coord:Vector.<Number> = new Vector.<Number>();

            //画线
			if(polylineStyle.dashMode)//虚线
			{
				var linepoints:ArrayCollection=new ArrayCollection();
				var point1:Pixel = null;
				var p1:PointGeometry = null;
				for(i=0;i<this.pointList.length;i++)
				{
					p1 = this.pointList.getItemAt(i) as PointGeometry;
					point1 = map.getLayerPxFromLocation(new Location(p1.x, p1.y));
					linepoints.addItem(point1);
				}
				
				var lengthsArray:Array=polylineStyle.dashMode.split(",");
				GMath.ConvertToDashLine(linepoints,star_commands,star_coord,lengthsArray);
			}
			else//实线
			{
				drawPolyline(map, 0, star_commands, star_coord);
			}
            sprite.graphics.drawPath(star_commands, star_coord); //GraphicsPathWinding.NON_ZERO

            //编辑状态显示锚点
            if (fea.editing) {
                drawAnchorPoint(sprite, map);
            }

        }

        /**
         * 画锚点
         * @includelastpoint 最后一个点是否画锚点
         */
        public function drawAnchorPoint(sprite:Sprite, map:Map, anchorindex:int = 0, includelastpoint:Boolean = true):void {
            var i:int = 0;
            var k:int = 0;
            var point:Pixel = null;
            var leng:int = this.pointList.length;
            var anchor:AnchorPoint;
            var bfind:Boolean = false;

            var anchorLayer:GraphicLayer = map.getLayerById(LayerIdConstants.ANCHORLAYER_LAYERID) as GraphicLayer;
            var numLayers:int = map.layers.length;
            if (map.getLayerIndex(anchorLayer) != numLayers - 1) {
                map.changeLayerIndex(anchorLayer, 0);
            }

            for (i = 0; i < leng; i++) {
                point = map.getLayerPxFromLocation(new Location(this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y));

                if (!includelastpoint && i == leng - 1) {
                    continue;
                }
                //trace("画锚点------------------------:" + point.x + "  " + point.y);
                bfind = false;

                var childnum:Number = anchorLayer.numChildren;
                for (k = 0; k < childnum; k++) {
                    if (anchorLayer.getChildAt(k) is AnchorPoint) {
                        if ((anchorLayer.getChildAt(k) as AnchorPoint).geoPoint == this.pointList.getItemAt(i)) {
                            //锚点已经存在
                            anchor = anchorLayer.getChildAt(k) as AnchorPoint;
                            bfind = true;
                        }
                    }

                }
                if (!bfind) {
                    anchor = new AnchorPoint();
                    anchorLayer.addChild(anchor);
                }
                anchor.x = point.x;
                anchor.y = point.y;
                anchor.pointIndex = anchorindex + i;
                anchor.parentFeature = sprite as Feature;
                anchor.geoPoint = this.pointList.getItemAt(i) as PointGeometry;

            }

        }

        /**
         * 画线
         * @param drawmode   drawmode>0:连着上一条线末端 继续画线；drawmode=0:从新开始画
         */
        public function drawPolyline(map:Map, drawmode:int, star_commands:Vector.<int>, star_coord:Vector.<Number>):void {
            var i:int = 0;
            var point1:Pixel = null;
            var point2:Pixel = null;
            var p1:PointGeometry = null;
            var p2:PointGeometry = null;
            var initialIndex:int = 0;
            var lastX:Number = -100000000;
            var lastY:Number = -100000000;

			
            //计算该线与当前mapextent相交的部分
            var mapExtent:Extent = map.extent;

            if (drawmode > 0 && this.pointList.length > 0) {
                initialIndex = 1;
                p1 = this.pointList.getItemAt(0) as PointGeometry;
                point1 = map.getLayerPxFromLocation(new Location(p1.x, p1.y));
                star_coord.push(point1.x);
                star_coord.push(point1.y);
                star_commands.push(2); //lineto
                //lastX = p1.x;
                //lastY = p1.y;
            }
		   /*
           for (i = initialIndex; i < this.pointList.length - 1; i++) {
                p1 = this.pointList.getItemAt(i) as PointGeometry;
                p2 = this.pointList.getItemAt(i + 1) as PointGeometry;
                //在当前窗口内，或者与当前窗口相交
                if (mapExtent.containsLineSection(p1, p2, (mapExtent.width / 2), (mapExtent.height / 2)) || mapExtent.crossLineSection(p1, p2, (mapExtent.width / 2), (mapExtent.height / 2))) {
                    if (i == 0 || lastX != p1.x || lastY != p1.y) {
                        point1 = map.getLayerPxFromLocation(new Location(p1.x, p1.y));
                        star_coord.push(point1.x);
                        star_coord.push(point1.y);
                        star_commands.push(1);
                        point2 = map.getLayerPxFromLocation(new Location(p2.x, p2.y));
                        star_coord.push(point2.x);
                        star_coord.push(point2.y);
                        star_commands.push(2);
                    }
                    else {
                        point2 = map.getLayerPxFromLocation(new Location(p2.x, p2.y));
                        star_coord.push(point2.x);
                        star_coord.push(point2.y);
                        star_commands.push(2);
                    }
                    lastX = p2.x;
                    lastY = p2.y;
                }

            }*/
			
			for (i = initialIndex; i < this.pointList.length; i++) {
				
				p1 = this.pointList.getItemAt(i) as PointGeometry;
				point1 = map.getLayerPxFromLocation(new Location(p1.x, p1.y));
				//在当前窗口内，或者与当前窗口相交
				star_coord.push(point1.x);
				star_coord.push(point1.y);
				if(i ==0)
				{
					star_commands.push(1);
				}
				else
				{
					star_commands.push(2);
				}
			}

        }


        /**
         * 得到几何体范围
         */
        override public function getExtent():Extent {
            var geoExtent:Extent = new Extent(0, 0, 0, 0);
            geoExtent.xmax = -999999999;
            geoExtent.xmin = 999999999;
            geoExtent.ymax = -999999999;
            geoExtent.ymin = 999999999;

            var pointGeo:PointGeometry = null;
            for (var j:int = 0; j < this.pointList.length; j++) {
                pointGeo = this.pointList.getItemAt(j) as PointGeometry;
                if (pointGeo.x > geoExtent.xmax) {
                    geoExtent.xmax = pointGeo.x;
                }
                if (pointGeo.x < geoExtent.xmin) {
                    geoExtent.xmin = pointGeo.x;
                }
                if (pointGeo.y > geoExtent.ymax) {
                    geoExtent.ymax = pointGeo.y;
                }
                if (pointGeo.y < geoExtent.ymin) {
                    geoExtent.ymin = pointGeo.y;
                }
            }
            return geoExtent;
        }

        override public function getGeometryType():int {
            return GeoTypeEnum.POLYLINEGEOMETRY;
        }

        public function get pointList():ArrayCollection {
            if (this._pointList == null) {
                this._pointList = new ArrayCollection();
            }
            return _pointList;
        }

        public function set pointList(value:ArrayCollection):void {
            _pointList = value;
        }


        /**
         * 判断点是否在线上
         * @param geom  参数几何体
         *
         */
        public function pointOnLine(geom:PointGeometry, delta:Number = 0.00001):Boolean {
            if (!geom) {
                return false;
            }
            var i:Number;
            for (i = 0; i < this.pointList.length - 1; i++) {
                if (GMath.pointOnLine(geom.x, geom.y, this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y, delta)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 判断线与线是否相交
         * @param geom  参数几何体
         * @param delta  容差
         */
        public function intersects(geom:IGeometry, delta:Number = 0.00001):Boolean {

            if (!geom) {
                return false;
            }

            var poly:PolylineGeometry = geom as PolylineGeometry;

            for (var i:int = 0; i < this.pointList.length - 1; i++) {
                for (var j:int = 0; j < poly.pointList.length - 1; j++) {
                    if (GMath.lineCross(poly.pointList.getItemAt(j).x, poly.pointList.getItemAt(j).y, poly.pointList.getItemAt(j + 1).x, poly.pointList.getItemAt(j + 1).y, this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y, delta)) {
                        return true;
                    }
                }
            }
            return false;
        }

        /**
         * 向指定的index增加point，默认末尾追加
         * */
        public function addPoint(point:PointGeometry, index:int = -1):void {
            if (index == -1) {
                this.pointList.addItem(point);
            }
            else {
                this.pointList.addItemAt(point, index);
            }

        }

        /**
         * 删除指定index的point，默认删除最后一个
         * */
        public function removePointByIndex(index:int = -1):void {
            if (this.pointList.length > 0) {
                if (index == -1) {
                    this.pointList.removeItemAt(pointList.length - 1);
                }
                else {
                    this.pointList.removeItemAt(index);
                }
            }
            else {
                return;
            }
        }

        public function getLastPoint():PointGeometry {
            if (this.pointList.length > 0) {
                return this.pointList.getItemAt(this.pointList.length - 1) as PointGeometry;
            }
            else {
                return null;
            }

        }

        public function getFirstPoint():PointGeometry {
            if (this.pointList.length > 0) {
                return this.pointList.getItemAt(0) as PointGeometry;
            }
            else {
                return null;
            }

        }

        override public function getTolerancePoint(mousePoint:PointGeometry, distance:Number, snapPoint:PointGeometry):int {
            var returnPoint:PointGeometry = new PointGeometry();
            //首先计算线上的端点，优先捕获端点，然后才是线上点，如果发现有端点捕获直接返回，不再计算线上点
            var lineDistance:Number;
            var isVertex:Boolean = false;
            for (var j:int = 0; j < this.pointList.length; j++) {
                returnPoint = PointGeometry(this.pointList.getItemAt(j));
                lineDistance = GMath.TwoPointDistance(mousePoint, returnPoint);
                if (lineDistance < distance) {
                    isVertex = true;
                    break;
                }
            }

            //计算线上点
            if (isVertex) {

                snapPoint.x = returnPoint.x;
                snapPoint.y = returnPoint.y;
                //trace(new Date()+"捕获到了顶点x:"+snapPoint.x+" y:"+snapPoint.y);
                //trace("捕获距离："+lineDistance+"容差是："+distance+"    鼠标点x:"+mousePoint.x+"y:"+mousePoint.y);
                return SnapTypeEnum.SNAP_OVERTEX;
            }
            else {
                var lineNearestPoint:PointGeometry = new PointGeometry();
                var bSnapRtLine:Boolean = GMath.NearestPntInPolyline(mousePoint, this, lineNearestPoint);
                lineDistance = GMath.TwoPointDistance(mousePoint, lineNearestPoint);
                //	trace("捕捉线上最近点距离:"+lineDistance);
                //trace("容差" + distance);
                if (lineDistance < distance) {

                    snapPoint.x = lineNearestPoint.x;
                    snapPoint.y = lineNearestPoint.y;
                    //trace(new Date()+"捕获到了线上点：x:"+snapPoint.x+" y:"+snapPoint.y);
                    //trace("捕获距离："+lineDistance+"容差是："+distance+"    鼠标点x:"+mousePoint.x+"y:"+mousePoint.y);
                    return SnapTypeEnum.SNAP_INLINE;
                }
                else {
                    //trace("未捕获到任何节点,："+"鼠标点x:"+mousePoint.x+"y:"+mousePoint.y);
                    //trace("捕获距离："+lineDistance+"容差是："+distance+"    鼠标点x:"+mousePoint.x+"y:"+mousePoint.y);
                    return SnapTypeEnum.NO_SNAPS;
                }
            }

        }

        public function toString():String {
            var str:String = "";
            for each (var point:PointGeometry in this._pointList) {
                str = str + "x:" + point.x + "y:" + point.y + "\n";
            }
            return str;
        }

        override public function getLabelLocation():Location {
            //最长一段的中间点
            var pointstart:PointGeometry;
            var pointend:PointGeometry;
            var maxlength:Number = -1;
            for (var i:int = 0; i < this.pointList.length - 1; i++) {
                if (GMath.lineLength(this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y) > maxlength) {
                    maxlength = GMath.lineLength(this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y);
                    pointstart = this.pointList.getItemAt(i) as PointGeometry;
                    pointend = this.pointList.getItemAt(i + 1) as PointGeometry;
                }
            }

            return new Location((pointstart.x + pointend.x) / 2, (pointstart.y + pointend.y) / 2);
        }

        override public function getLabelAngle():Number {
            //最长一段的中间点
            var lineangle:Number = 0;
            var labelAngle:Number = 0;
            var pointstart:PointGeometry;
            var pointend:PointGeometry;
            var maxlength:Number = -1;
            for (var i:int = 0; i < this.pointList.length - 1; i++) {
                if (GMath.lineLength(this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y) > maxlength) {
                    maxlength = GMath.lineLength(this.pointList.getItemAt(i).x, this.pointList.getItemAt(i).y, this.pointList.getItemAt(i + 1).x, this.pointList.getItemAt(i + 1).y);
                    pointstart = this.pointList.getItemAt(i) as PointGeometry;
                    pointend = this.pointList.getItemAt(i + 1) as PointGeometry;
                }
            }
            //线的角度
            lineangle = GMath.lineAngle(pointstart.x, pointstart.y, pointend.x, pointend.y);

            //标注的角度   标注的角度是与Y轴正向的夹角
            if ((lineangle >= 270 && lineangle <= 360) || (lineangle >= 0 && lineangle <= 90)) {
                labelAngle = -lineangle;
            }
            else {
                //避免标注符号倒过来显示
                labelAngle = -lineangle + 180;
            }
            return labelAngle;
        }

        override public function offset(location:Location):void {
            for each (var point:PointGeometry in this._pointList) {
                point.offset(location);
            }
        }

        override public function removePoint(point:PointGeometry):void {
            if (this._pointList.length < 3) {
                Alert.show("This is the minimum number of nodes for feature, can not be deleted", "warning", Alert.OK);
                return;
            }

            for (var i:int = 0; i < this._pointList.length; i++) {
                if (this._pointList.getItemAt(i) == point) {
                    this._pointList.removeItemAt(i);
                    break;
                }
            }
        }

        override public function isValid():Boolean {
            if (this.pointList.length < 2) {
                return false;
            }
            return true;
        }

        override public function hasPoint(point:PointGeometry):Boolean {
            if (this._pointList == null || !isValid()) {
                return false;
            }
            for (var i:int = 0; i < this._pointList.length; i++) {
                var linePoint:PointGeometry = this._pointList.getItemAt(i) as PointGeometry;
                if (linePoint.hasPoint(point)) {
                    return true;
                }
            }
            return false;
        }

		public function get duration():Number
		{
			return _duration;
		}
		
		public function set duration(value:Number):void
		{
			_duration=value;
		}
    }
}